package com.spring.aop.xml;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

/**
 * @author liangd
 * date 2020-11-16 17:40
 * code 基于配置文件配置AOP
 */
public class LoggingAspect {


    public void beforeMethod(JoinPoint joinPoint) {
        //获取切入点方法名
        String methodName = joinPoint.getSignature().getName();
        //获取切入点方法参数
        List<Object> args = Arrays.asList(joinPoint.getArgs());

        System.out.println("The method " + methodName + " begins with " + args);
    }

    /**
     * 后置通知：在目标方法之后执行（无论是否发生异常），执行的通知
     * 不能访问目标方法执行的结果
     */
    public void afterMethod(JoinPoint joinPoint) {
        //获取切入点方法名
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method " + methodName + " ends with");
    }

    /**
     * 返回通知:可以访问目标方法执行的结果
     *
     * @param joinPoint 切入点
     * @param result    返回结果
     */
    public void afterReturning(JoinPoint joinPoint, Object result) {

        String methodName = joinPoint.getSignature().getName();

        System.out.println("The method " + methodName + " returning with " + result);
    }

    /**
     * 异常通知：在方法抛出异常的时候执行
     */
    public void afterThrowing(JoinPoint joinPoint, Exception e) {
        String methodName = joinPoint.getSignature().getName();

        System.out.println("The method " + methodName + " occurs throwing with " + e);
    }

    /**
     * 环绕通知：相当于动态代理的全过程（功能最强大，但并不代表经常使用）
     * <p>
     * 环绕通知需要ProceedingJoinPoint 参数，参数的类型可以决定是否执行目标方法
     * 环绕通知必须有返回值，且返回值为目标方法的返回值
     *
     * @param pjp 参数类型
     * @return object
     */
    public Object aroundMethod(ProceedingJoinPoint pjp) {

        Object result = null;
        String methodName = pjp.getSignature().getName();

        try {
            //前置通知
            System.out.println("The method (around) " + methodName + " begins with " + Arrays.asList(pjp.getArgs()));
            result = pjp.proceed();
            //返回通知
            System.out.println("The method (around) " + methodName + " returning with " + result);
        } catch (Throwable throwable) {
            //异常通知
            System.out.println("The method (around) " + methodName + " occurs throwing with " + throwable);
        }
        //后置通知
        System.out.println("The method (around) " + methodName + " ends with");
        return result;
    }
}
